#include "BitBuffer.h"
#include <stdio.h>
#include <string>
#include <math.h>

BitBuffer::BitBuffer(void)
{
	size = 0;
	bitsPushed = 0;
	buffer = NULL;
}

BitBuffer::BitBuffer(unsigned int size, unsigned int symbolSize)
{
	bitMask = 0x80;
	currentByte = 0;
	bitsPushed = 0;
	this->size = size;
	this->symbolSize = symbolSize;
	buffer = new unsigned char[size];
	for (unsigned int i = 0; i < size; ++i)
	{
		buffer[i] = 0;
	}
}

BitBuffer::BitBuffer(unsigned char* buffer, unsigned int size, unsigned int numberOfBits, unsigned int symbolSize)
{
	bitMask = 0x80;
	currentByte = 0;
	bitsPushed = 0;
	this->size = size;
	this->symbolSize = symbolSize;
	this->bitsPushed = numberOfBits;
	this->buffer = buffer;
}

BitBuffer::BitBuffer(const BitBuffer& buffer)
{
	this->bitMask = buffer.bitMask;
	this->currentByte = buffer.currentByte;
	this->size = buffer.size;
	this->symbolSize = buffer.symbolSize;
	this->buffer = new unsigned char[size];
	memcpy(this->buffer, buffer.buffer, size);
	this->bitsPushed = buffer.bitsPushed;
}

BitBuffer::~BitBuffer(void)
{
	if (buffer)
	{
		delete[] buffer;
	}
}

void BitBuffer::appendBit(unsigned char bit)
{
	if (bit)
	{
		buffer[currentByte] |= bitMask;
	}
	bitMask >>= 1;
	if (bitMask == 0)
	{
		++currentByte;
		bitMask = 0x80;
	}
	++bitsPushed;
}

unsigned char BitBuffer::popBit()
{
	if (bitMask == 0)
	{
		if(currentByte<size-1) ++currentByte;
		bitMask = 0x80;
	}
	char popBit = buffer[currentByte] & bitMask;
	if (popBit)
	{
		popBit = 0x01;
	}
	else
	{
		popBit = 0x00;
	}
	bitMask >>= 1;
	--bitsPushed;
	return popBit;
}

void  BitBuffer::getBits(BitBuffer *bufferToPlaceBits, int firstBitIndex, int bitCount)
{
	int byte = firstBitIndex * 0.125;
	int bitOffset = firstBitIndex % 8;
	unsigned char bMask=0x80;
	bMask >>= bitOffset;

	unsigned char *chosenBits = bufferToPlaceBits->getBuffer();

	for(int i=0; i<size; ++i)
		chosenBits[i]=0x00;

	for(int i=0; i<bitCount; i++)
	{
		chosenBits[byte] |= (buffer[byte] & bMask);
		bMask >>= 1;

		if(bMask==0x00)
		{
			bMask=0x80;
			++byte;
		}
	}
}

unsigned char BitBuffer::getBit(int index)
{
	int byte = index * 0.125;
	int bitOffset = index % 8;
	unsigned char bMask=0x80;
	bMask >>= bitOffset;

	char bit = buffer[byte] & bMask;
	if (bit)
	{
		bit = 0x01;
	}
	else
	{
		bit = 0x00;
	}

	return bit;
}

void BitBuffer::setBit(unsigned char bit, int index)
{
	int byte = index * 0.125;
	int bitOffset = index % 8;
	unsigned char bMask=0x80;
	bMask >>= bitOffset;

	if (bit)
	{
		buffer[byte]|=bMask;
	}
	else
	{
		bMask=~bMask;
		buffer[byte]&=bMask;
	}
}

void BitBuffer::printBuffer()
{
	unsigned char printMask = 0x80;
	unsigned char shiftMask = 7;
	for (unsigned int i = 0; i < size * 8; ++i)
	{
		printf("%d", (buffer[i / 8] & printMask) >> shiftMask);
		printMask >>= 1;
		--shiftMask;
		if (printMask == 0)
		{
			printMask = 0x80;
			shiftMask = 7;
		}
	}
}

unsigned char* BitBuffer::getBuffer()
{
	return buffer;
}

int BitBuffer::getSize()
{
	return size;
}

void BitBuffer::resetPointers()
{
	currentByte = 0;
	bitMask = 0x80;
}

bool BitBuffer::hasBits()
{
	return bitsPushed > 0;
}

unsigned int BitBuffer::popSymbol()
{
	unsigned int result = 0;
	for (unsigned int i = 0; i < symbolSize && bitsPushed > 0; ++i)
	{
		result |= popBit();
		result <<= 1;
	}
	return result;
}

void BitBuffer::pushSymbol(unsigned int symbol)
{
	for (unsigned int i = 0; i < symbolSize; ++i)
	{
		appendBit(symbol);
		symbol >>= 1;
	}
}

unsigned int BitBuffer::numberOfBits()
{
	return bitsPushed;
}

BitBuffer& BitBuffer::operator=(const BitBuffer& buffer)
{
	this->bitMask = buffer.bitMask;
	this->currentByte = buffer.currentByte;
	this->size = buffer.size;
	this->symbolSize = buffer.symbolSize;
	this->buffer = new unsigned char[size];
	memcpy(this->buffer, buffer.buffer, size);
	this->bitsPushed = buffer.bitsPushed;
	return *this;
}
